package com.googlecode.jkorpos.lingpipe;

import com.aliasi.corpus.Parser;
import com.aliasi.corpus.TagHandler;

import com.aliasi.hmm.HmmCharLmEstimator;
import com.aliasi.hmm.HmmDecoder;
import com.aliasi.hmm.HmmEvaluation;
import com.aliasi.hmm.HmmEvaluator;

import com.aliasi.util.Reflection;

import java.io.File;
import java.io.IOException;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.xml.sax.InputSource;

public class EvaluatePos {
    final int mSentEvalRate;
    final int mToksBeforeEval;
    final int mMaxNBest;
    final int mNGram;
    final int mNumChars;
    final double mLambdaFactor;
    final PosCorpus mCorpus;

    final HashSet mTagSet = new HashSet();
    HmmCharLmEstimator mEstimator;
    HmmEvaluator mEvaluator;
    int mTrainingSentenceCount = 0;
    int mTrainingTokenCount = 0;

    public EvaluatePos(String[] args) {
        mSentEvalRate = Integer.parseInt(args[0]);
        mToksBeforeEval = Integer.parseInt(args[1]);
        mMaxNBest = Integer.parseInt(args[2]);
        mNGram = Integer.parseInt(args[3]);
        mNumChars = Integer.parseInt(args[4]);
        mLambdaFactor = Double.parseDouble(args[5]);
        String constructorName = args[6];
        File corpusFile = new File(args[7]);
        Object[] consArgs = new Object[] { corpusFile };
        mCorpus = (PosCorpus) Reflection.newInstance(constructorName,consArgs);
    }

    void run() throws IOException {
        System.out.println("\nCOMMAND PARAMETERS:");
        System.out.println("  Sent eval rate=" + mSentEvalRate);
        System.out.println("  Toks before eval=" + mToksBeforeEval);
        System.out.println("  Max n-best eval=" + mMaxNBest);
        System.out.println("  Max n-gram=" + mNGram);
        System.out.println("  Num chars=" + mNumChars);
        System.out.println("  Lambda factor=" + mLambdaFactor);

        CorpusProfileHandler profileHandler = new CorpusProfileHandler();
        parseCorpus(profileHandler);
        String[] tags = (String[]) mTagSet.toArray(new String[0]);
        Arrays.sort(tags);
        System.out.println("\nCORPUS PROFILE:");
        System.out.println("  Corpus class=" + mCorpus.getClass().getName());
        System.out.println("  #Sentences="
                           + mTrainingSentenceCount);
        System.out.println("  #Tokens=" + mTrainingTokenCount);
        System.out.println("  #Tags=" + tags.length);
        System.out.println("  Tags=" + Arrays.asList(tags));

        System.out.println("\nEVALUATION:");
        mEstimator
            = new HmmCharLmEstimator(mNGram,mNumChars,mLambdaFactor);
        for (int i = 0; i < tags.length; ++i)
            mEstimator.addState(tags[i]);


        mEvaluator
            = new HmmEvaluator(mEstimator,tags,mMaxNBest);
        LearningCurveHandler evaluationHandler
            = new LearningCurveHandler();
        parseCorpus(evaluationHandler);
    }

    void parseCorpus(TagHandler handler) throws IOException {
        Parser parser = mCorpus.parser();
        parser.setHandler(handler);
        Iterator it = mCorpus.sourceIterator();
        while (it.hasNext()) {
            InputSource in = (InputSource) it.next();
            parser.parse(in);
        }
    }

    class CorpusProfileHandler implements TagHandler {
        public void handle(String[] toks, String[] whitespaces,
                           String[] tags) {
            ++mTrainingSentenceCount;
            mTrainingTokenCount += toks.length;
            for (int i = 0; i < tags.length; ++i)
                mTagSet.add(tags[i]);
        }
    }

    class LearningCurveHandler implements TagHandler {
        public void handle(String[] toks, String[] whites, String[] refTags) {
            if (mEstimator.numTrainingTokens() > mToksBeforeEval
                && mEstimator.numTrainingCases() % mSentEvalRate == 0) {

                mEvaluator.handle(toks,whites,refTags);
                System.out.println("\nTest Case "
                                   + mEvaluator.evaluation().numCases());
                // System.out.println(mEvaluator.lastCaseToString());
                System.out.println("Cumulative Evaluation");
                System.out.print("    Estimator:  #Train Cases="
                                 + mEstimator.numTrainingCases());
                System.out.println(" #Train Toks="
                                   + mEstimator.numTrainingTokens() + "]");
                System.out.print("    Evaluator:  ");
                System.out.println(mEvaluator.evaluation().toString());
            }
            // train
            mEstimator.handle(toks,whites,refTags);
            for (int i = 0; i < toks.length; ++i)
                mEvaluator.evaluation().addKnownToken(toks[i]);
        }
    }

    public static void main(String[] args)
        throws IOException, ClassNotFoundException {

        new EvaluatePos(new String[]{
        		"1",
        		"170000",
        		"100",
        		"12",
        		"3000",
        		"8.0",
        		"com.googlecode.jkorpos.lingpipe.SejongPosCorpus",
        		"data/sejong/"
        }).run();
    }

}
